package com.gitee.wsl.android.ext

import android.content.Context
import android.graphics.*
import android.graphics.Bitmap.CompressFormat
import android.graphics.drawable.*
import android.graphics.drawable.shapes.RoundRectShape
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import androidx.annotation.Px
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable
import com.gitee.wsl.android.drawable.ScaleDrawable
import com.gitee.wsl.android.ext.ApplicationInit.application
import com.gitee.wsl.math.ScaleStyle
import java.io.*


object DrawableExt{
     val BITMAP_PAINT :Paint by lazy { Paint(Paint.FILTER_BITMAP_FLAG) }

    /**
     * 创建一张渐变图片，支持韵脚。
     *
     * @param startColor 渐变开始色
     * @param endColor   渐变结束色
     * @param radius     圆角大小
     * @param centerX    渐变中心点 X 轴坐标
     * @param centerY    渐变中心点 Y 轴坐标
     * @return 返回所创建的渐变图片。
     */

    fun createCircleGradientDrawable(
        @ColorInt startColor: Int,
        @ColorInt endColor: Int, radius: Float,
        @FloatRange(from = 0.0, to = 1.0) centerX: Float,
        @FloatRange(from = 0.0, to = 1.0) centerY: Float
    ): GradientDrawable {
        val gradientDrawable = GradientDrawable()
        gradientDrawable.colors = intArrayOf(
            startColor,
            endColor
        )
        gradientDrawable.gradientType = GradientDrawable.RADIAL_GRADIENT
        gradientDrawable.gradientRadius = radius
        gradientDrawable.setGradientCenter(centerX, centerY)
        return gradientDrawable
    }


    /**
     * 动态创建带上分隔线或下分隔线的Drawable。
     *
     * @param separatorColor 分割线颜色。
     * @param bgColor        Drawable 的背景色。
     * @param top            true 则分割线为上分割线，false 则为下分割线。
     * @return 返回所创建的 Drawable。
     */
    fun createItemSeparatorBg(
        @ColorInt separatorColor: Int,
        @ColorInt bgColor: Int,
        separatorHeight: Int,
        top: Boolean
    ): LayerDrawable {
        val separator = ShapeDrawable()
        separator.paint.style = Paint.Style.FILL
        separator.paint.color = separatorColor
        val bg = ShapeDrawable()
        bg.paint.style = Paint.Style.FILL
        bg.paint.color = bgColor
        val layers = arrayOf<Drawable>(separator, bg)
        val layerDrawable = LayerDrawable(layers)
        layerDrawable.setLayerInset(
            1,
            0,
            if (top) separatorHeight else 0,
            0,
            if (top) 0 else separatorHeight
        )
        return layerDrawable
    }

    fun isEmptyBitmap(src: Bitmap?): Boolean {
        return src == null || src.width == 0 || src.height == 0
    }

    fun createShapeDrawable(image:Bitmap, radius:Float = 10f):ShapeDrawable{
        val shapeDrawable = ShapeDrawable(
            RoundRectShape(
                floatArrayOf(
                    radius,
                    radius,
                    radius,
                    radius,
                    radius,
                    radius,
                    radius,
                    radius
                ), null, null
            )
        )
        val bitmapShader = BitmapShader(image, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        shapeDrawable.paint.shader = bitmapShader
        return shapeDrawable
    }

    /**
     * 创建 StateListDrawable
     * @param selected 选中状态
     * @param pressed  按下状态
     * @param focused  获取焦点状态
     * @param checked  已勾选状态
     * @param normal   默认状态
     * @return [StateListDrawable]
     */
    fun newSelector(
        normal: Drawable,
        selected: Drawable?,
        pressed: Drawable?,
        focused: Drawable?,
        checked: Drawable?
    ): StateListDrawable {
        // 创建 StateListDrawable
        val stateListDrawable = StateListDrawable()
        selected?.let { stateListDrawable.addState(intArrayOf(android.R.attr.state_selected), it) }
        pressed?.let { stateListDrawable.addState(intArrayOf(android.R.attr.state_pressed), it) }
        focused?.let {  stateListDrawable.addState(intArrayOf(android.R.attr.state_focused), focused)}
        checked?.let {  stateListDrawable.addState(intArrayOf(android.R.attr.state_checked), checked)}
        stateListDrawable.addState(intArrayOf(), normal)
        return stateListDrawable
    }

    /**
     * Helper to create an [StateListDrawable] for the given normal and pressed color
     *
     * @param normalColor  the normal color
     * @param pressedColor the pressed color
     * @return the [StateListDrawable]
     */
    @JvmStatic
    fun getStateListDrawable(normalColor: Int, pressedColor: Int): StateListDrawable {
        val states = StateListDrawable()
        states.addState(intArrayOf(android.R.attr.state_pressed),
            ColorDrawable(pressedColor))
        states.addState(intArrayOf(android.R.attr.state_focused),
            ColorDrawable(pressedColor))
        states.addState(intArrayOf(android.R.attr.state_activated),
            ColorDrawable(pressedColor))
        states.addState(intArrayOf(),
            ColorDrawable(normalColor))
        return states
    }

    /**
     * helper to create a stateListDrawable for the icon
     *
     * @param icon
     * @param selectedIcon
     * @return
     */
    fun getIconStateList(icon: Drawable, selectedIcon: Drawable): StateListDrawable {
        val iconStateListDrawable = StateListDrawable()
        iconStateListDrawable.addState(intArrayOf(android.R.attr.state_selected), selectedIcon)
        iconStateListDrawable.addState(intArrayOf(), icon)
        return iconStateListDrawable
    }

}

fun createBitmap( width:Number,  height:Number,  config:Bitmap.Config = Bitmap.Config.ARGB_8888):Bitmap {
    return Bitmap.createBitmap(width.toInt(), height.toInt(), config)
}


fun Context.loadBase64Drawable(data:String):Drawable{
    return data.base64ToBitmap().toDrawable(resources)
}

fun Drawable.centerAt(x: Float, y: Float) {
    val drawableHalfWidth = this.intrinsicWidth / 2
    val drawableHalfHeight = this.intrinsicHeight / 2
    this.setBounds(
        x.toInt() - drawableHalfWidth,
        y.toInt() - drawableHalfHeight,
        x.toInt() + drawableHalfWidth,
        y.toInt() + drawableHalfHeight
    )
}

fun Drawable.toBitmapOrNull(
    @Px width: Int = intrinsicWidth,
    @Px height: Int = intrinsicHeight,
    config: Bitmap.Config? = null
): Bitmap? {
    if (this is BitmapDrawable && bitmap == null) return null
    return toBitmap(width, height, config)
}

/**
 * Drawable to bitmap.
 *
 * @param drawable The drawable.
 * @return bitmap
 */
fun Drawable.drawable2Bitmap(): Bitmap {
    if (this is BitmapDrawable) {
        if (bitmap != null) {
            return bitmap
        }
    }
    val bitmap: Bitmap = if (intrinsicWidth <= 0 || intrinsicHeight <= 0) {
        Bitmap.createBitmap(
            1, 1,
            if (opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
        )
    } else {
        Bitmap.createBitmap(
            intrinsicWidth,
            intrinsicHeight,
            if (opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
        )
    }
    val canvas = Canvas(bitmap)
    setBounds(0, 0, canvas.width, canvas.height)
    draw(canvas)
    return bitmap
}

fun Drawable.crop(pos:RectF, zoom:Float=1f): Bitmap? {

    val matrix = Matrix()

    // Scaling to base zoom level (zoom == 1)
    matrix.postScale(1f / zoom, 1f / zoom, pos.left, pos.top)

    // Positioning crop area
    matrix.postTranslate(-pos.left, -pos.top)

    return try {
        // Draw drawable into bitmap
        val dst = createBitmap(pos.width(), pos.height(), Bitmap.Config.ARGB_8888)
        val canvas = Canvas(dst)
        canvas.concat(matrix)
        draw(canvas)
        dst
    } catch (e: OutOfMemoryError) {
        null // Not enough memory for cropped bitmap
    }

}

/**
 * Bitmap to drawable.
 *
 * @return drawable
 */
fun Bitmap.bitmap2Drawable( ): Drawable {
    return BitmapDrawable(application.resources, this)
}

/**
 * Drawable to bytes.
 *
 * @return bytes
 */
fun Drawable.drawable2Bytes(): ByteArray {
    return drawable2Bitmap().bitmap2Bytes()
}

/**
 * Drawable to bytes.
 *
 * @param format   The format of bitmap.
 * @return bytes
 */
fun Drawable.drawable2Bytes( format: CompressFormat = CompressFormat.JPEG, quality: Int=1): ByteArray {
    return  drawable2Bitmap().bitmap2Bytes(format, quality)
}

/**
 * Bytes to drawable.
 *
 * @return drawable
 */
fun ByteArray.bytes2Drawable(): Drawable {
    return bytes2Bitmap().bitmap2Drawable()
}

fun Drawable.toScaleDrawable(scaleStyle: ScaleStyle = ScaleStyle.FIT): ScaleDrawable = ScaleDrawable(this,scaleStyle)

fun Drawable.drawWithColorFilter(canvas: Canvas, colorFilter: ColorFilter?) {
    val cf = this.colorFilter
    this.colorFilter = colorFilter
    this.draw(canvas)
    this.colorFilter = cf
}

fun LayerDrawable.getDrawableOrNull(index: Int): Drawable? {
    return try {
        this.getDrawable(index)
    } catch (e: IndexOutOfBoundsException) {
        return null
    }
}